package com.googlecode.spoluyan.google.common;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Utils {
    private static Gson GSON;
    static {
	GsonBuilder gson = new GsonBuilder();
	for (Class<?> cl : Defines.customJSONAdapters.keySet()) {
	    gson.registerTypeHierarchyAdapter(cl, Defines.customJSONAdapters.get(cl));
	}
	GSON = gson.create();
    }

    public static boolean isEmptyString(String string) {
	return (string == null || string.trim().length() == 0);
    }

    public static void closeQuietly(Closeable closeable) {
	try {
	    if (closeable != null) {
		closeable.close();
	    }
	} catch (IOException ioe) {
	}
    }

    public static String toJSON(Object obj) {
	return GSON.toJson(obj);
    }

    public static String doRequest(Map<String, String> queryParams, String... restParams) {
	return doRequest(null, queryParams, restParams);
    }

    public static String doRequest(String key, Map<String, String> queryParams, String... restParams) {
	return getResponseAsString(generateURL(key, queryParams, restParams));
    }

    public static String generateURL(String key, Map<String, String> queryParams, String... restParams) {
	StringBuilder sb = new StringBuilder(Defines.EMPTY_STRING);
	for (String p : restParams) {
	    sb.append(p);
	}

	if (queryParams != null || !isEmptyString(key)) {
	    sb.append(Defines.QUESTION_MARK);
	    if (queryParams != null) {
		for (String p : queryParams.keySet()) {
		    String value;
		    try {
			value = URLEncoder.encode(queryParams.get(p), Defines.ENCODING);
		    } catch (UnsupportedEncodingException e) {
			value = Defines.EMPTY_STRING;
		    }
		    sb.append(p).append(Defines.EQUALS_SIGN).append(value).append(Defines.AMPERSAND);
		}
	    }
	    if (!isEmptyString(key)) {
		String value;
		try {
		    value = URLEncoder.encode(key, Defines.ENCODING);
		} catch (UnsupportedEncodingException e) {
		    value = Defines.EMPTY_STRING;
		}
		sb.append(Defines.API_KEY_PARAM).append(Defines.EQUALS_SIGN).append(value);
	    } else {
		if (queryParams != null) {
		    sb.deleteCharAt(sb.length() - 1);
		}
	    }
	}
	return sb.toString();
    }

    public static String getResponseAsString(String urlString) {
	byte[] data = getDataFromURL(urlString);
	if (data == null) {
	    return null;
	}
	try {
	    return new String(data, Defines.ENCODING);
	} catch (UnsupportedEncodingException e) {
	    return null;
	}
    }

    public static byte[] getDataFromURL(String urlString) {
	try {
	    URL url = new URL(urlString);
	    URLConnection conn = url.openConnection();
	    conn.connect();
	    return getDataFromOpenedConnection(conn);
	} catch (Exception e) {
	}
	return null;
    }

    public static byte[] getDataFromOpenedConnection(URLConnection conn) {
	InputStream in = null;
	ByteArrayOutputStream out = null;
	byte[] data = null;
	try {
	    in = conn.getInputStream();
	    out = new ByteArrayOutputStream();

	    byte[] byteChunk = new byte[4096];
	    int n;

	    while ((n = in.read(byteChunk)) > 0) {
		out.write(byteChunk, 0, n);
	    }

	    data = out.toByteArray();

	    out.close();
	    in.close();

	    return data;
	} catch (Exception e) {
	} finally {
	    closeQuietly(out);
	    closeQuietly(in);
	}
	return data;
    }

    public static <T> T fromJSON(String json, Class<T> clazz) {
	return (T) GSON.fromJson(json, clazz);
    }
}
